﻿using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using System.Linq.Expressions;

namespace Microsoft.EntityFrameworkCore
{
    /// <summary>
    /// Converts nullable bool values to and from their string representation.
    /// </summary>
    public class NullableBoolToStringConverter : ValueConverter<bool?, string>
    {
        public NullableBoolToStringConverter(string trueValue, string falseValue,
            bool isIgnoreCase = true,
            [CanBeNull] ConverterMappingHints mappingHints = null)
            : base(
                ToString(falseValue, trueValue, isIgnoreCase),
                ToBoolNullable(trueValue, isIgnoreCase),
                mappingHints)
        {

        }

        private static Expression<Func<bool?, string>> ToString(string falseValue, string trueValue, bool isIgnoreCase)
        {
            if (trueValue == falseValue || (isIgnoreCase && trueValue.ToLower() == falseValue.ToLower()))
            {
                throw new ArgumentException("trueValue and falseValue cannot be equal.");
            }

            return value => value.HasValue ? (value.Value ? trueValue : falseValue) : null;
        }

        private static Expression<Func<string, bool?>> ToBoolNullable(string trueValue, bool isIgnoreCase)
        {
            if (!isIgnoreCase)
            {
                return value => string.IsNullOrWhiteSpace(value) ? (bool?)null : (trueValue == value);
            }

            trueValue = trueValue.ToLower();
            return value => string.IsNullOrWhiteSpace(value) ? (bool?)null : (value.ToLower() == trueValue);
        }
    }
}
